﻿//
// util.hpp
// ~~~~~~~~
//

#ifndef YUTOPP_OAUTH_UTILITY_UTILITY_HPP
#define YUTOPP_OAUTH_UTILITY_UTILITY_HPP

#include <string>
#include <vector>
#include <fstream>
#include <iterator>
#include <map>

#include <boost/xpressive/xpressive.hpp>
#include <boost/xpressive/regex_actions.hpp>

#include <boost/random.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/foreach.hpp>

namespace webapp
{
	namespace util
	{
		//適当にランダムな値を返す。
		template<int Min = 0, int Max = 148822011/*magic number*/>
		class random
		{
			typedef int num_type;

		public:
			random()
				: gen_( boost::make_shared<boost::mt19937>() )
				, dist_( Min, Max )
			{}

			num_type operator()() const	//どうしてもconstつけたい・・・！
			{
				return dist_( *gen_ );
			}

		private:
			boost::shared_ptr<boost::mt19937> gen_;
			boost::random::uniform_int_distribution<> dist_;
		};

		//
		int hex_to_dec( const std::string& str )
		{
			static const std::string table( "0123456789ABCDEF" );
			std::locale loc;
			int ret = 0;

			const auto last = str.cend();
			for( auto it = str.cbegin(); it < last; ++it ) {
				ret = ret * 16 + table.find( std::toupper( *it, loc ) );
			}
			return ret;
		}

		//
		std::string inline make_boundary_string()
		{
			static util::random<> rnd;
			return "--------------" + boost::lexical_cast<std::string>( rnd() );
		}

		template<typename Range, typename charT>
		std::basic_string<charT> catenate_map(
			const Range& args,
			const charT* f,
			const charT* l,
			const bool do_last_cut = true )
		{
			return (catenate_map<Range, charT>)(
				args,
				std::basic_string<charT>( f ),
				std::basic_string<charT>( l ),
				do_last_cut
				);
		}
		template<typename Range, typename charT>
		std::basic_string<charT> catenate_map(
			const Range& args,
			const std::basic_string<charT>& f,
			const std::basic_string<charT>& l,
			const bool do_last_cut = true )
		{
			std::basic_string<charT> ret;
			BOOST_FOREACH( const typename Range::value_type& v, args ) {
				if ( !v.second.empty() )
					ret += v.first + f + v.second + l;
			}
			if ( do_last_cut && !ret.empty() )
				ret.erase( ret.end() - l.size() );
			
			return ret;
		}


		template<typename charT>
		std::map<std::basic_string<charT>, std::basic_string<charT> >
			parse_url_encoded_text( const std::basic_string<charT>& body )
		{
			namespace xsv = boost::xpressive;
			typedef std::basic_string<charT>	string_type;

			std::map<string_type, string_type> v;
			
			const xsv::sregex pair =
				( ( xsv::s1 = +xsv::_w ) >> '=' >> ( xsv::s2 = -+xsv::_ ) )
					[ xsv::ref( v )[xsv::s1] = xsv::s2 ];
			const xsv::sregex items = pair >> *( '&' >> pair );	
			xsv::regex_match( body, items );
   
			return v;
		}

		template<>
		std::map<std::basic_string<wchar_t>, std::basic_string<wchar_t> >
			parse_url_encoded_text( const std::basic_string<wchar_t>& body )
		{
			namespace xsv = boost::xpressive;
			typedef std::basic_string<wchar_t>	string_type;

			std::map<string_type, string_type> v;
			
			const xsv::wsregex pair =
				( ( xsv::s1 = +xsv::_w ) >> L'=' >> ( xsv::s2 = -+xsv::_ ) )
					[ xsv::ref( v )[xsv::s1] = xsv::s2 ];
			const xsv::wsregex items = pair >> *( L'&' >> pair );	
			xsv::regex_match( body, items );

			return v;
		}

		//
		std::vector<char> load_binary_file( const std::string& file_name )
		{
			std::vector<char> bin;

			std::ifstream fs( file_name, std::ios::binary );
			if ( !fs )
				return bin;
			const std::istreambuf_iterator<char> begin = fs, end;
			std::copy( begin, end, std::back_inserter( bin ) );

			return bin;
		}
	} // - util
}

#endif /*YUTOPP_OAUTH_UTILITY_UTILITY_HPP*/
